package cn.mill.core;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.mill.common.Builder;
import cn.mill.common.Listener;
import cn.mill.common.Node;
import cn.mill.common.Protocol;
import cn.mill.common.Resolver;
import cn.mill.common.Spell;
import cn.mill.common.Strategy;
import cn.mill.common.exception.MillException;
import cn.mill.core.node.DefaultNode;
import cn.mill.core.utils.ConfigBuilder;

public class MillConfig implements Serializable {
	private static final Logger logger = LoggerFactory.getLogger(MillConfig.class);
	private static final long serialVersionUID = -5258333923083414671L;
	private static final ConcurrentHashMap<Type, Spell> INDEX = new ConcurrentHashMap<Type, Spell>();
	private static final ConcurrentHashMap<String, Strategy<?, ?>> STRATEGY_INDEX = new ConcurrentHashMap<String, Strategy<?, ?>>();
	private static final ConcurrentHashMap<String, Protocol<?, ?>> PROTOCOL_INDEX = new ConcurrentHashMap<String, Protocol<?, ?>>();
	private static final ConcurrentHashMap<String, Node> NODE_INDEX = new ConcurrentHashMap<String, Node>();
	
	static {
		init();
	}
	
	public static void init() {
		logger.info("=================mill init start============================");
		for (String line : Constants.BANNER) {
			logger.info(line);
		}
		ConfigBuilder cb = new ConfigBuilder();
		NODE_INDEX.putAll(cb.NodeBuilder());
		PROTOCOL_INDEX.putAll(cb.ProtocolBuilder());
		STRATEGY_INDEX.putAll(cb.StrategyBuilder());
		INDEX.putAll(cb.SpellBuilder());
		logger.info("=================mill init Ok================================");
	}
	
	public static Node getNode(String name) {
		Node n = NODE_INDEX.get(Constants.NODE + name);
		return n == null ? new DefaultNode() : n;
	}
	
	public static Protocol<?, ?> getProtocol(String name) throws MillException {
		Protocol<?, ?> p = PROTOCOL_INDEX.get(name);
		if (p == null) {
			throw new MillException("not found Protocol[" + name + "]");
		}
		return p;
	}
	
	public static Strategy<?, ?> getStrategy(String name) throws MillException {
		Strategy<?, ?> s = STRATEGY_INDEX.get(name);
		if (s == null) {
			throw new MillException("not found Strategy[" + name + "]");
		}
		return s;
	}
	
	public static Resolver getResolver(Type type) {
		Resolver resolver = (Resolver) INDEX.get(type);
		if (resolver != null) {
			return resolver;
		} else if (type instanceof Class && type instanceof Object) {
			return (Resolver) INDEX.get(Object.class);
		} else if (type instanceof ParameterizedType) {
			Type rawType = ((ParameterizedType) type).getRawType();
			return rawType instanceof Class ? getResolver((Class<?>) rawType) : getResolver(rawType);
		} else {
			return (Resolver) INDEX.get(Object.class);
		}
	}
	
	public static Builder getBuilder(Type type) {
		Builder builder = (Builder) INDEX.get(type);
		if (builder != null) {
			return builder;
		} else if (type instanceof Class && type instanceof Object) {
			return (Builder) INDEX.get(Object.class);
		} else if (type instanceof ParameterizedType) {
			Type rawType = ((ParameterizedType) type).getRawType();
			return rawType instanceof Class ? getBuilder((Class<?>) rawType) : getBuilder(rawType);
		} else {
			return (Builder) INDEX.get(Object.class);
		}
	}
	
	public static Listener getListener() {
		return DefaultListener.INSTANCE;
	}
}
